# -*- coding: utf-8 -*-

import struct
import re
import os
import math
from tkinter import *
from tkinter import ttk

def str_align(ret, type = 0, al_len = 8):
	len_align = math.ceil(len(ret)/al_len) * al_len
	str_add  = "0"
	print(ret, len_align, len_add)
	if type == 1:
		str_add = ret[-1]
	out = ret.rjust(len_align, str_add)
	#print(out)
	return out

def str_align32(ret, type = 0):
	str_add  = "0"
	if type == 1:
		str_add = ret[-1]
	out = ret.rjust(32, str_add)
	out = out[0:8] + "_" + out[8:16] + "_" + out[16:24] + "_" + out[24:32];
	return out

def str_align16(ret, type = 0):
	str_add  = "0"
	if type == 1:
		str_add = ret[-1]
	out = ret.rjust(16, str_add)
	out = out[0:8] + "_" + out[8:16] 
	return out

def float_to_hex_fp16(i: str) -> str:
	f = float(i)
	h = hex(struct.unpack('<H', struct.pack('<e', f))[0])
	#return hex_num
	return str(h)[2:]

def hex_fp16_to_float(hex_data: str):
	ori_data = struct.unpack('!e', bytes.fromhex(hex_data))[0]
	return str(ori_data)

def float_to_hex(i: str) -> str:
	f = float(i)
	h = hex(struct.unpack('<I', struct.pack('<f', f))[0])
	return str(h)[2:]

def hex_to_float(hex_data: str) -> str: #in fp32: 3eb33333
	ori_data = struct.unpack('!f', bytes.fromhex(hex_data))[0]
	return str(ori_data)

def dec_to_bin(i: str) -> str:
	if not isinstance(i, str):
		raise TypeError("Not str input")
	return format(int(i),'b')#08b

def bin_to_dec(i: str) -> str:
	if not isinstance(i, str):
		raise TypeError("Not str input")
	return str(int(str(i), 2))

def dec_to_bnr(i: int, lenth: int = 1) -> str:
	if not isinstance(i, str):
		raise TypeError("Not str input")
	dec = int(i)
	digits = (len(bin(dec)) - 3 + 1) if dec < 0 else (len(bin(dec)) - 2)
	if digits >= lenth:
		lenth = digits
	pattern = f"{dec & int('0b' + '1' * lenth, 2):0{lenth}b}"
	return "".join(code for code in pattern)

def bnr_to_dec(i: str) -> str:
	if not isinstance(i, str):
		raise TypeError("Not str input")
	for num in i:
		if num not in ["0", "1"]:
			raise ValueError("Not bin str")
	if i.startswith("0"):
		dec = int(i, 2)
	else:
		dec = int(i[1:], 2) - 0x01
		dec = -(~dec & int("0b" + "1" * (len(i) - 1), 2))
	return str(dec)

def dec_to_hex(i: str) -> str:
	if not isinstance(i, str):
		raise TypeError("Not str input")
	if i.startswith("-"):
		i = re.sub("-", "", i)
		return "-" + str(hex(int(i)))[2:]
	else:
		return str(hex(int(i)))[2:]

def bin_to_bnr(i: str) -> str:
	return dec_to_bnr(bin_to_dec(i))

def bin_to_hex(i: str) -> str:
	if not isinstance(i, str):
		raise TypeError("Not str input")
	if i.startswith("-"):
		i = re.sub("-", "", i)
		return "-" + str(hex(int(i, 2)))[2:]
	else:
		return str(hex(int(i, 2)))[2:]

def bnr_to_bin(i: str) -> str:
	return dec_to_bin(bnr_to_dec(i))

def bnr_to_hex(i: str) -> str:
	return dec_to_hex(bnr_to_dec(i))

def hex_to_dec(i: str) -> str:
	if not isinstance(i, str):
		raise TypeError("Not str input")
	return str(int(i, 16))

def hex_to_bin(i: str) -> str:
	return dec_to_bin(hex_to_dec(i))

def hex_to_bnr(i: str) -> str:
	return dec_to_bnr(hex_to_dec(i))

def tk_main():
	global mode
	mode = 0
	
	def choose(event): #选择框事件
		global mode
		mode = com.current()
	pass
	
	def start_trans():
		d  = "-无效-" #十进制
		h  = "-无效-" #十六进制
		b  = "-无效-" #二进制
		n  = "-无效-" #补码二进制
		nh = "-无效-" #补码十六进制
		
		fh = "-无效-" #FP32十六进制
		fb = "-无效-" #FP32二进制
		
		f16h = "-无效-" #FP16十六进制
		f16b = "-无效-" #FP16二进制
		
		value = txt_in.get(1.0, "end").strip()
		if len(value) == 0:
			value = "0"
		else:
			value = str(value)
		if re.search(r"\.", value):#浮点数
			d  = value
			fh = float_to_hex(value)
			fb = str_align32(hex_to_bin(fh))
			f16h = float_to_hex_fp16(value)
			f16b = str_align16(hex_to_bin(f16h))
		else:
			if mode == 0:#十进制
				#print("DEC")
				d  = value
				h  = dec_to_hex(value)
				b  = dec_to_bin(value)
				n  = dec_to_bnr(value)
				nh = bin_to_hex(n)
				fh = float_to_hex(value)
				fb = str_align32(hex_to_bin(fh))
				f16h = float_to_hex_fp16(value)
				f16b = str_align16(hex_to_bin(f16h))
			elif mode == 1:#十六进制
				print("HEX")
				d  = hex_to_dec(value)
				h  = value
				b  = hex_to_bin(value)
				n  = hex_to_bnr(value)
				nh = bin_to_hex(n)
			elif mode == 2:#二进制
				print("BIN")
				d  = bin_to_dec(value)
				h  = bin_to_hex(value)
				b  = value
				n  = bin_to_bnr(value)
				nh = bin_to_hex(n)
			elif mode == 3:#二进制补码
				print("BNR")
				d  = bnr_to_dec(value)
				h  = bnr_to_hex(value)
				b  = bnr_to_bin(value)
				n  = value
				nh = bin_to_hex(n)
			elif mode == 4:#FP32十六进制
				d = hex_to_float(value)
				fh = float_to_hex(d)
				fb = str_align32(hex_to_bin(fh))
				f16h = float_to_hex_fp16(d)
				f16b = str_align16(hex_to_bin(f16h))
			elif mode == 5:#FP16十六进制
				d = hex_fp16_to_float(value)
				fh = float_to_hex(d)
				fb = str_align32(hex_to_bin(fh))
				f16h = float_to_hex_fp16(d)
				f16b = str_align16(hex_to_bin(f16h))
			pass#end re.search(r"\.", value):#浮点数
		txt0.delete(0.0, END)
		txt0.insert(1.0, d)
		txt1.delete(0.0, END)
		txt1.insert(1.0, h)
		txt2.delete(0.0, END)
		txt2.insert(1.0, b)
		txt3.delete(0.0, END)
		txt3.insert(1.0, n)
		txt4.delete(0.0, END)
		txt4.insert(1.0, nh)
		
		txt5.delete(0.0, END)
		txt5.insert(1.0, fh)
		txt6.delete(0.0, END)
		txt6.insert(1.0, fb)
		
		txt7.delete(0.0, END)
		txt7.insert(1.0, f16h)
		txt8.delete(0.0, END)
		txt8.insert(1.0, f16b)
	pass
	
	root = Tk()
	root.geometry("400x300")
	root.title("进制转换器GUI From GJM")
	
	#选择输入的进制和数值
	f1 = Frame(root, height = 100, width = 300)
	f1.pack(pady=1)
	#创建下拉菜单
	xVariable = StringVar()
	com = ttk.Combobox(f1, textvariable=xVariable, cursor="arrow")
	com["value"] = ("十进制", "十六进制", "二进制", "补码二进制", "FP32十六进制", "FP16十六进制")
	com.current(0)
	com.bind("<<ComboboxSelected>>", choose)
	com.pack(side = LEFT)
	#数值框
	txt_in = Text(f1, height=1)
	txt_in.pack(side = RIGHT, padx=10)
	
	#展示区	
	f2 = Frame(root, height = 100, width = 300, relief=RIDGE)
	f2.pack(fill=X, pady=1)
	label0 = Label(f2,text='十进制').pack(side=LEFT)
	txt0 = Text(f2,width = 40, height = 1)
	txt0.pack(side=RIGHT, padx=10)

	f3 = Frame(root, height = 100, width = 300)
	f3.pack(fill=X, pady=1)
	label1 = Label(f3,text='十六进制').pack(side=LEFT)
	txt1 = Text(f3,width = 40, height = 1)
	txt1.pack(side=RIGHT, padx=10)
	
	f4 = Frame(root, height = 100, width = 300)
	f4.pack(fill=X, pady=1)
	label2 = Label(f4,text='二进制').pack(side=LEFT)
	txt2 = Text(f4,width = 40, height = 1)
	txt2.pack(side=RIGHT, padx=10)
	
	f5 = Frame(root, height = 100, width = 300)
	f5.pack(fill=X, pady=1)
	label3 = Label(f5,text='补码二进制').pack(side=LEFT)
	txt3 = Text(f5,width = 40, height = 1)
	txt3.pack(side=RIGHT, padx=10)
	
	f6 = Frame(root, height = 100, width = 300)
	f6.pack(fill=X, pady=1)
	label4 = Label(f6,text='补码十六进制').pack(side=LEFT)
	txt4 = Text(f6,width = 40, height = 1)
	txt4.pack(side=RIGHT, padx=10)
	
	f7 = Frame(root, height = 100, width = 300)
	f7.pack(fill=X, pady=1)
	label5 = Label(f7,text='FP32十六进制').pack(side=LEFT)
	txt5 = Text(f7,width = 40, height = 1)
	txt5.pack(side=RIGHT, padx=10)
	
	f8 = Frame(root, height = 100, width = 300)
	f8.pack(fill=X, pady=1)
	label6 = Label(f8,text='FP32二进制').pack(side=LEFT)
	txt6 = Text(f8,width = 40, height = 1)
	txt6.pack(side=RIGHT, padx=10)
	
	f9 = Frame(root, height = 100, width = 300)
	f9.pack(fill=X, pady=1)
	label7 = Label(f9,text='FP16十六进制').pack(side=LEFT)
	txt7 = Text(f9,width = 40, height = 1)
	txt7.pack(side=RIGHT, padx=10)
	
	f10 = Frame(root, height = 100, width = 300)
	f10.pack(fill=X, pady=1)
	label8 = Label(f10,text='FP16二进制').pack(side=LEFT)
	txt8 = Text(f10,width = 40, height = 1)
	txt8.pack(side=RIGHT, padx=10)
	
	fx = Frame(root, height = 100, width = 300)
	fx.pack(pady=10)
	button1 = Button(fx, text='确定', command=start_trans)
	button1.pack(side=LEFT, padx=10)
	button2 = Button(fx, text='退出', command=root.quit)
	button2.pack(side=RIGHT, padx=10)
	
	root.mainloop()

if __name__ == '__main__':
	tk_main()
